const { src, dest, parallel, series, watch } = require('gulp');
const del = require('del');
/**
 * 1. browser-sync自动编译并且自动刷新浏览器页面，减少在开发阶段的重复操作从而提高开发效率
 * 2. browser-sync不是gulp的模块，只是通过gulp去管理它而已
 */
const browserSync = require('browser-sync');
const bs = browserSync.create();//创建一个开发服务器
const loadPlugins = require('gulp-load-plugins');//这是一个方法
const plugins = loadPlugins();//这是一个对象，所有的插件方法都是这个对象的一个属性


const data = {
  menus: [
    {
      name: 'home',
      icon: 'aperture',
      link: 'index.html',
    },
    {
      name: 'about',
      link: 'about.html',
    },
  ],
  pkg: require('./package.json'),
  date: new Date(),
}

//清除文件
const clean = () => {
  return del(['dist', 'temp']);
}


//style是一个私有任务，并不能通过gulp去执行，必须通过module.exports导出出去
//对样式文件的编译
const style = () => {
  //dest指的是目标位置
  return src('src/assets/styles/*.scss', { base: 'src' })
    .pipe(plugins.sass({ outputStyle: 'expanded' }))
    .pipe(dest('temp'))
    .pipe(bs.reload({ stream: true }));
}

//对脚本语言ES6语法的编译
const script = () => {
  return src('src/assets/scripts/*.js', { base: 'src' })
    .pipe(plugins.babel({ presets: ['@babel/preset-env'] }))
    .pipe(dest('temp'))
    .pipe(bs.reload({ stream: true }));
}

//对页面模版编译：
const page = () => {
  // src/**/*.html：代表src下的任意子目录的html文件
  return src('src/*.html', { base: 'src' })
    .pipe(plugins.swig({ data }))
    .pipe(dest('temp'))
    .pipe(bs.reload({ stream: true }));
}

//对图片进行转换:对图片进行无损压缩(也就是看到的效果是一样的),只是删除了一些yuan数据的信息
const image = () => {
  return src('src/assets/images/**', { base: 'src' })
    .pipe(plugins.imagemin())
    .pipe(dest('dist'));
}

//对字体进行转换
const font = () => {
  return src('src/assets/fonts/**', { base: 'src' })
    .pipe(plugins.imagemin())
    .pipe(dest('dist'));
}

const extra = () => {
  return src('public/**', { base: 'public' })
    .pipe(dest('dist'));
}

const serve = () => {

  /**
   * 1. watch去监视配置的路径通配符，当文件发生了变化，则去触发第二个参数(执行相对应的任务)
   * 2. style、script、page、image、font、extra这些任务一旦触发了之后，就会把dist中相对应的文件覆盖掉
   * 3. 一旦覆盖掉，则browser-sync就会监视到temp文件的变化(files: 'temp/**'),然后就会自动同步到浏览器
   */

  watch('src/assets/styles/*.scss', style);//对样式文件的监视
  watch('src/assets/scripts/*.js', script);//对js文件的监视
  watch('src/*.html', page);//对html文件的监视

  /**
   * 在开发阶段：
   * 对image，font，extra这些任务的构建是没有太大意义的。
   * 因为图片和字体我们只是对它做了一个压缩，这个压缩只是一个无损压缩并不影响在页面当中的呈现。
   * 在开发阶段去监视更多的文件去做更多的任务你的开销也就会更大，而这个开销对于开发阶段是没有意义的
   * 只需要在发布之前(上线之前)，减小上线的文件体积，从而提高网站运行的效率。
   * 但是在开发阶段这么处理的话会增大项目构建的效率，所以一般在开发阶段不会去构建这些文件
   * 
   * 具体做法(开发阶段)：
   * baseDir指定两个目录，一个是temp目录，一个是src目录(在开发阶段不让图片、字体、public等额外的文件参与项目的构建)
   * baseDir指定为一个数组。当它被指定为一个数组之后，当发生请求时，它会先从第一个目录下去找对应的文件，如果找不到则会依次往后找
   * 
   * 当图片、字体或者public文件发生变化时，如何更新浏览器的问题：
   * 具体方法：
   * 1. 使用一个watch,减少构建的次数
   * 2. 使用bs.reload方法执行(bs.reload是一个函数，在gulp当中一个函数就是一个任务，所以这里就是执行了一个任务)
   * 3. 当这些文件发生变化之后，自动更新浏览器，浏览器会重新发起对这些文件的请求，这样就可以拿到最新的文件
   */
  // watch('src/assets/images/**',image);//对图片的监视
  // watch('src/assets/images/**'font);//对字体的监视
  // watch('public/**',extra);//对public文件的监视
  watch([
    'src/assets/images/**',
    'src/assets/images/**',
    'public/**',
  ], bs.reload);

  //bs.init初始化这个web服务器的一些相关服务配置
  bs.init({
    notify: false,
    port: 2080,//端口
    open: true,//是否自动打开浏览器,默认true
    /**
     * 1. files：被browser-sync监听的路径
     * 2. 可以替换为在每个任务后添加一个pipe(bs.reload({stream:true}))
     */
    // files: 'temp/**',
    //核心配置server需要指定网站的根目录
    server: {

      /**
       * 1. temp目录下的文件是加工后的结果，给浏览器的代码肯定是temp目录下的
       * 2. baseDir被指定为一个数组之后，当发出请求时它会到数组中的第一个目录下去找那个文件，如果找不到那个文件则会依次往后去找
       */
      baseDir: ['temp', 'src', 'public'],

      //routes配置优先于baseDir,当发生请求时会优先看routes下有没有对应的配置，如果有则会先走routes里面的配置，否则再去找baseDir下的配置
      routes: {
        '/node_modules': 'node_modules',
      }

    }
  });
}

/**
 * useref(使用的依赖):
 * 1. 处理的是压缩过后的文件，所以在temp下找文件
 * 2. useref会自动的处理我们html文件中的构建注释，如果在同一个注释标签中引用多个文件则会将这些引用的资源做一个合并，打包在一块
 * 3. useref修改了html文件，并且把html中依赖的文件生成了一些新的文件在项目当中
 * 4. 我们需要借助一些插件对这些新生成的文件进行压缩：
 *    比如：
 *    a. html:gulp-htmlmin
 *    b. js:gulp-uglify
 *    c. css:gulp-clean-css
 * 5. 对新生成的文件进行压缩的问题：
 *    a. 这些文件有可能有html,js,css，我们需要区分它到底是哪类文件，然后才可进行压缩，此时我们需要借助gulp-if插件去帮我们区分
 * 6. 清除html的换行符和空格： collapseWhitespace 设置为true
 * 7. html文件的行内样式：minifyCSS设置为true
 * 8. html文件的js代码：minifyJS设置为true
 * 
 * 重新规划构建过程：
 * 1. 在useref之前，压缩的那些文件都是中间产物，所以在开发时我们不能把这些文件放在dist文件中，应该放在一个temp文件中
 */

const useref = () => {
  return src('temp/*.html', { base: 'temp' })
    .pipe(plugins.useref({ searchPath: ['temp', '.'] }))
    .pipe(plugins.if(/\.js$/, plugins.uglify()))
    .pipe(plugins.if(/\.css$/, plugins.cleanCss()))
    .pipe(plugins.if(/\.html$/, plugins.htmlmin({
      collapseWhitespace: true,
      minifyCSS: true,
      minifyJS: true,
    })))
    .pipe(dest('dist'));
}


//compile 大多是把src下的文件做些转换
const compile = parallel(style, script, page);

/**
 * 1. build 完成所有文件的转换
 * 2. series顺序执行，此时会先执行clean，再执行parallel(compile, extra)
 * 3. build 可以理解为上线之前执行的任务
 */
const build = series(
  clean,
  parallel(
    series(compile, useref),
    image,
    font,
    extra
  )
);

/**
 * 1. develop开发中执行的任务。
 * 2. 优化：在开发阶段没有必要去构建图片，字体，public下的文件，这些只需要在上线之前构建就可以了，节约资源提高开发效率
 * 3. 开发阶段只需要启动样式，脚本，模版就可以
 */
const develop = series(compile, serve);

module.exports = {
  clean,
  build,
  develop,
}